/**
 * Copyright 1996 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 *
 * Note, this is a very old runtime library that I have evolved since 1996. I rarely use it
 * now because the Apache Commons project has made it obsolete.
 */
package self.net;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;


public class UriEncoderUtils {

	private static final byte[] uri_char_validity = new byte[] {
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 1, 0, 0, 1, 0, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
	    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,
	
	    /* 64 */
	    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
	    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,
	    0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
	    1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,
	
	    /* 128 */
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	
	    /* 192 */
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	    0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
	  };

    /**
     * tests whether a string contains any XML unsafe characters
     * that we need to encode 
     * @param testString string to test
     * @return true if the string is OK, false if encoding is necessary
     */
    public static boolean isSafe(String testString)  {
        if (testString == null) {
            return true;
        }
        for (int i=0; i<testString.length(); i++) {
            if (uri_char_validity[testString.charAt(i)] ==0) {
                return false;
            }
        }
        return true;
    }

	public static String encodeUri(String src) {
	    StringBuffer sb = null;
	    byte[] bytes;
	    try {
	        bytes = src.getBytes("UTF-8");
	    } catch (UnsupportedEncodingException e) {
	        bytes = src.getBytes();
	    }
	    for (int i = 0; i < bytes.length; i++) {
	        int index = bytes[i] & 0xFF;
	        if (UriEncoderUtils.uri_char_validity[index] > 0) {
	            if (sb != null) {
	                sb.append((char) bytes[i]);
	            }
	            continue;
	        }
	        if (sb == null) {
	            sb = new StringBuffer();
	            sb.append(new String(bytes, 0, i));
	        }
	        sb.append("%");
	
	        sb.append(Character.toUpperCase(Character.forDigit((index & 0xF0) >> 4, 16)));
	        sb.append(Character.toUpperCase(Character.forDigit(index & 0x0F, 16)));
	    }
	    return sb == null ? src : sb.toString();
	}

	public static String decodeUri(String src) {
	    // this is string in ASCII-US encoding.
	    boolean query = false;
	    boolean decoded = false;
	    ByteArrayOutputStream bos = new ByteArrayOutputStream(src.length());
	    for(int i = 0; i < src.length(); i++) {
	        byte ch = (byte) src.charAt(i);
	        if (ch == '?') {
	            query = true;
	        } else if (ch == '+' && query) {
	            ch = ' ';
	        } else if (ch == '%' && i + 2 < src.length() &&
	                   UriEncoderUtils.isHexDigit(src.charAt(i + 1)) &&
	                   UriEncoderUtils.isHexDigit(src.charAt(i + 2))) {
	            ch = (byte) (UriEncoderUtils.hexValue(src.charAt(i + 1))*0x10 + UriEncoderUtils.hexValue(src.charAt(i + 2)));
	            decoded = true;
	            i += 2;
	        }
	        bos.write(ch);
	    }
	    if (!decoded) {
	        return src;
	    }
	    try {
	        return new String(bos.toByteArray(), "UTF-8");
	    } catch (UnsupportedEncodingException e) {
	        e.printStackTrace();
	    }
	    return src;
	}

	private static boolean isHexDigit(char ch) {
	    return Character.isDigit(ch) ||
	           (Character.toUpperCase(ch) >= 'A' && Character.toUpperCase(ch) <= 'F');
	}

	private static int hexValue(char ch) {
	    if (Character.isDigit(ch)) {
	        return ch - '0';
	    }
	    ch = Character.toUpperCase(ch);
	    return (ch - 'A') + 0x0A;
	}
}
